
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include "xrn_common.h"
#include "xrn_common_backend.h"

// CRC function for 8 bits
void xrn_crc8( uint8_t * data, int length, uint8_t * crc
 )
{
    for ( size_t i = 0; i < length; i++ ) {
        ( *crc ) = CRC8_TABLE[( *crc ) ^ data[i]];
    }

}

// CRC function for 16 bits
void xrn_crc16( uint8_t * data, int length, uint16_t * crc
 )
{
    for ( size_t i = 0; i < length; i++ ) {
        ( *crc ) = ( uint16_t ) ( ( ( *crc ) << 8 ) ^ CRC16_TABLE[( ( ( *crc ) >> 8 ) ^ data[i] ) & 0xff] );
    }

}

// CRC function for 32 bits
void xrn_crc32( uint8_t * data, int length, uint32_t * crc
 )
{
    for ( size_t i = 0; i < length; i++ ) {
        ( *crc ) = ( ( *crc ) << 8 ) ^ CRC32_TABLE[( ( ( *crc ) >> 24 ) ^ data[i] ) & 0xff];
    }

}

// CRC function for 64 bits
void xrn_crc64( uint8_t * data, int length, uint64_t * crc
 )
{
    for ( size_t i = 0; i < length; i++ ) {
        ( *crc ) = ( ( *crc ) << 8 ) ^ CRC64_TABLE[( ( ( *crc ) >> 56 ) ^ data[i] ) & 0xff];
    }

}

#pragma GCC push_options
#pragma GCC optimize ("O0")

void xrn_free( void *ptr, uint64_t size
 )
{

    int i;

    for ( i = 0; i < size; i++ ) {
        ( ( uint8_t * ) ptr )[i] = ( uint8_t ) ( rand(  ) % 256 );
    }

    free( ptr );

    return;
}

#pragma GCC pop_options

int xrn_feof( FILE * fp
 )
{

    uint64_t pos;
    uint64_t eofpos;

    pos = ( uint64_t ) ftell( fp );
    if ( 0 != fseek( fp, 0, SEEK_END ) ) {
        return 0;
    }

    eofpos = ( uint64_t ) ftell( fp );

    if ( 0 != fseek( fp, ( int64_t ) pos, SEEK_SET ) ) {
        return 0;
    }

    if ( eofpos == pos ) {
        return 1;
    }

    return 0;
}

void xrn_load_sub_type( uint8_t subtype, uint8_t * crc_bytes, int *nbits
 )
{

    subtype = ( uint8_t ) ( ( subtype ) & 0x07 );
    *crc_bytes = ( subtype >> 1 );
    *nbits = ( ( ( subtype & 0x01 ) + 1 ) * 128 );

    return;

}

void xrn_dump_sub_type( uint8_t * subtype, uint8_t crc_bytes, int nbits
 )
{

    // *subtype = ( uint8_t ) ((*subtype) & 0xf8);
    *subtype = 0;
    *subtype = ( uint8_t ) ( ( crc_bytes & 0x03 ) << 1 );
    *subtype = ( uint8_t ) ( ( *subtype ) | ( ( ( nbits / 128 - 1 ) ) & 0x01 ) );

    return;

}

void print_header_block( header_block_t header
 )
{

    printf( "header.magic_number %u\n", header.magic_number );
    printf( "header.tag %u\n", header.tag );
    printf( "header.offset %lu\n", header.offset );
    printf( "header.length %lu\n", header.length );
    printf( "header.total_length %lu\n", header.total_length );

}

uint8_t cksumnum_buff_crc8( uint8_t buff_index, cksumnum_t * chsumnum_buff
 )
{

    uint8_t xcrc8;

    xcrc8 = 0xff;
    xrn_crc8( ( uint8_t * ) & chsumnum_buff[buff_index],
              ( int ) ( ( XRN_CHKSUM_BUFF - buff_index ) * ( ( int ) sizeof( cksumnum_t ) ) ), &xcrc8 );
    xrn_crc8( ( uint8_t * ) & chsumnum_buff[0], ( int ) ( buff_index * ( ( int ) sizeof( cksumnum_t ) ) ),
              &xcrc8 );

    return xcrc8;

}

int get_random_bytes( uint8_t * buffer, uint32_t len
 )
{

#if ( XCOMPILETESTS == 1 )

    int i;

    for ( i = 0; i < len; i++ ) {
        buffer[i] = ( uint8_t ) ( rand(  ) % 256 );
    }

    return XSUCCESS;
#endif

#if ( XRN_GNU_LINUX == 1 )
    FILE *fp;
    uint32_t n;

    fp = fopen( "/dev/urandom", "rb" );
    if ( fp != NULL ) {
        n = ( uint32_t ) fread( buffer, sizeof( uint8_t ), len, fp );
        if ( n < len ) {

            //error cant read correctly urand
            XPRINT_ERR( 1989, XERR_IO_MSG );
            if ( 0 != fclose( fp ) ) {
                XPRINT_ERR( 1990, XERR_IO_MSG );
                return XERR_IO;
            }

            return XERR_IO;
        }

        if ( 0 != fclose( fp ) ) {
            XPRINT_ERR( 1991, XERR_IO_MSG );
            return XERR_IO;
        }

        return XSUCCESS;
    } else {
        XPRINT_ERR( 1992, XERR_IO_MSG );
        return XERR_IO;
    }

#else
    BCRYPT_ALG_HANDLE hAlg;

    if ( !BCRYPT_SUCCESS( BCryptOpenAlgorithmProvider( &hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0 ) ) ) {
        XPRINT_ERR( 1993, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( !BCRYPT_SUCCESS
         ( BCryptGenRandom( hAlg, ( PUCHAR ) ( buffer ), len, BCRYPT_RNG_USE_ENTROPY_IN_BUFFER ) ) ) {
        XPRINT_ERR( 1994, XERR_IO_MSG );
        return XERR_IO;
    }

    BCryptCloseAlgorithmProvider( hAlg, 0 );
    return XSUCCESS;

#endif
}

